//
//  CZRefreshControl.swift
//  新浪微博
//
//  Created by Jack.Lin on 16/7/8.
//  Copyright © 2016年 Jack.Lin. All rights reserved.
//

import UIKit

// 刷新状态的临界点
  private let CZRefreshOffset: CGFloat = 126

// 刷新状态
enum CZRefreshState {
    case Normal
    case Pulling
    case WillRefresh
}


class CZRefreshControl: UIControl {


    // MARK - 属性
    // 刷新控件的父视图, 下拉刷新控件应该使用 UITableView / UICollectionView
    private weak var scrollView: UIScrollView?
    
    // 刷新视图
    private lazy var refresView: JKRefreshView = JKRefreshView.refreshView()
    
    // MARK - 构造函数
    init() {
        super.init(frame: CGRect())
        
        setupUI()
    }
    
    // xib 的加载方法, 但是先执行 awake , 执行时, 视图未加载
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        setupUI()
    }
    
    /**
     willMove addSubview 方法会调用
     - 当添加到父视图的时候, newSuperview 是父视图
     - 当父视图被移除, newSuperview 是 nil
    */
    
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        // 判断父视图的类型
        guard let sv = newSuperview as? UIScrollView else {
            return
        }
        
        scrollView = sv
        
        // KVO 监听父视图 contentOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
    }

    // 本视图从父视图上移除
    // 提示: 所有的下拉刷新框架都是监听父视图的 contentOffset
    // 所有的框架的 KVO 监听实现思路都是这个
    override func removeFromSuperview() {
        // superView 还存在
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        
        super.removeFromSuperview()
    }
    
    // 所有 KVO 方法会统一调用此方法
    // 观察者模式, 在不需要的时候, 都需要释放
    // - 通知中心: 如果不释放, 什么也不会发生, 但是会有内存泄露, 会有多次注册的可能!
    // - KVO: 如果不释放, 会崩溃
    override func observeValue(forKeyPath keyPath: String?, of object: AnyObject?, change: [NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer<Void>?) {
        
        // contentOffset 的 y 值跟 contentInset 的 top 有关
        
        guard let sv = scrollView else {
            return
        }
        // 初始高度应该是 0 
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        
        if height < 0 {
            return
        }
        
        // 可以根据高度设置刷新控件的 frame
        self.frame = CGRect(x: 0,
                            y: -height,
                            width: sv.bounds.width,
                            height: height)
    
//        print(height)
        // 传递父视图高度
//        refresView.parentViewHeight = height
        
        if refresView.refreshState != .WillRefresh {
            refresView.parentViewHeight = height
        }
        
        // 判断临界点 - 只需要判断一次
        
        if sv.isDragging {
            if height > CZRefreshOffset && (refresView.refreshState == .Normal) {
                print("放手刷新")
          
                refresView.refreshState = .Pulling
                }
        } else if height <= CZRefreshOffset && (refresView.refreshState == .Pulling) {
            print("继续使劲...")
            refresView.refreshState = .Normal
        } else {
        
            if refresView.refreshState == .Pulling {
                print("准备开始刷新")
                
                // 刷新结束之后，将 状态修改为 .Normal 才能够继续响应刷新
//                refresView.refreshState = .WillRefresh
                
                beginRefreshing()
                // 发送刷新数据事件
                sendActions(for: .valueChanged)

            }
        }
        
    }
    
    
    /// 开始刷新
    func beginRefreshing() {
        print("开始刷新")
        
        guard let sv = scrollView else {
            return
        }
        
        // 判断刷新视图的状态，如果是 .WillRefresh 表示刷新还没有完成
        if refresView.refreshState == .WillRefresh {
            return
        }
        
        // 设置刷新状态
        refresView.refreshState = .WillRefresh

        
        var inset = sv.contentInset
        inset.top += CZRefreshOffset
        
        // 会触发表格视图的 contentOffset 的变化
        sv.contentInset = inset
        
        // 如果开始调用 beginRefresh 会重复发送刷新事件
        //sendActions(for: .valueChanged)

    }
    
    /// 结束刷新
    func endRefreshing() {
        print("结束刷新")
        
        guard let sv = scrollView else {
            return
        }
        
        // 判断状态，是否正在刷新，如果不是，直接返回
        if refresView.refreshState != .WillRefresh {
            return
        }
        
        refresView.refreshState = .Normal
        
        var inset = sv.contentInset
        inset.top -= CZRefreshOffset
        
        sv.contentInset = inset
        
    }
}

extension CZRefreshControl {

    private func setupUI() {
       backgroundColor = superview?.backgroundColor
        
        // 设置超出边界不显示
//        clipsToBounds = true
        
        // 添加刷新视图 - xib加载出来的, 默认是xib中指定的宽高
        addSubview(refresView)
        
        // 自动布局 - Xib 控件的自动布局, 需要指定宽高约束
        refresView.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraint(NSLayoutConstraint(item: refresView,
                                         attribute: .centerX,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .centerX,
                                         multiplier: 1.0,
                                         constant: 0))
        addConstraint(NSLayoutConstraint(item: refresView,
                                         attribute: .bottom,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .bottom,
                                         multiplier: 1.0,
                                         constant: 0))
        addConstraint(NSLayoutConstraint(item: refresView,
                                         attribute: .width,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refresView.bounds.width))
        addConstraint(NSLayoutConstraint(item: refresView,
                                         attribute: .height,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refresView.bounds.height))
    }
}

